//七、闭包: 能够访问自由变量的函数
//自由变量：在函数中使用的，但既不是函数参数也不是函数局部变量的变量。
//闭包 = 函数 + 函数能够访问的自由变量
//闭包可以从一个函数内部访问其外部函数的作用域。即使外部函数已经执行完毕，内部函数仍然可以访问外部函数的变量

//理论角度: 所有的JavaScript函数都是闭包
//实践角度:
/*
* 1.即使创建它的上下文已经销毁，它仍然存在
* 2.代码中引用了自由变量
* */

// 示例
//外部函数
function outerFunction(outerVariable){
    //内部函数(闭包)
    return function innerFunction(innerVariable){
        console.log('外部变量:' + outerVariable);  // 自由变量
        console.log('内部变量:' + innerVariable);  // 函数参数
    }
}

//创建闭包
const closure = outerFunction('外部值');
//调用闭包,即时outerFunction函数已经执行完毕   外部值仍然被保留
// innerFunction仍然可以访问outerVariable
closure('内部值'); // 输出: 外部变量:外部值  内部变量:内部值

//闭包的实际应用
//1.数据封装
//使用闭包创建私有变量，防止外部直接访问
function createCounter(){
    let count = 0;
    return {
        increment: function (){
            count++;
            return count;
        },
        decrement:function (){
            count --;
            return count;
        },
        getValue:function (){
            return count;
        }
    };
}

const counter = createCounter();
console.log(counter.getValue()); // 0
counter.increment();
console.log(counter.getValue()); //1
//2.函数工厂
//使用闭包创建具体特定配置的函数
function createMultiplier(multiplier){
    return function (x){
        return x * multiplier;
    }
}
const double = createMultiplier(2);
const triple = createMultiplier(3);

console.log(double(5)); //10
console.log(triple(5)); //15
//3.事件处理
//在事件处理程序中保持对特定数据的访问

function setupButtons(){
    for(var i = 0;i< 5;i++){
        //使用闭包保存每个按钮的索引
        (function(index){
            document.getElementById('btn-' + index).addEventListener('click',function (){
                alert('按钮' + index +　'被点击了')
            })
        })(i);
    }
}
